package com.ljc.service;

import com.alibaba.fastjson.JSONObject;
import com.ljc.constant.UserConstant;
import com.ljc.entity.PageResult;
import com.ljc.entity.RefreshTokenDetail;
import com.ljc.entity.User;
import com.ljc.entity.UserInfo;
import com.ljc.exception.ConditionException;
import com.ljc.interfaces.UserApi;
import com.ljc.utils.MD5Util;
import com.ljc.utils.RSAUtil;
import com.ljc.utils.TokenUtil;
import io.seata.spring.annotation.GlobalTransactional;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class UserService {
    @DubboReference
    private UserApi userApi;
    @Resource
    private UserAuthService userAuthService;

    /**
     * 添加用户和设置用户基本信息
     */
    @GlobalTransactional(rollbackFor = Exception.class)
    public void addUser(User user) {
        // 校验
        String phone = user.getPhone();
        if (StringUtils.isEmpty(phone)) {
            throw new ConditionException("手机号不能为空！");
        }
        User dbUser = userApi.getUserByPhone(phone);
        if (dbUser != null) {
            throw new ConditionException("该手机号已经注册！");
        }
        // 根据时间对密码进行加盐
        Date now = new Date();
        String salt = String.valueOf(now.getTime());
        String password = user.getPassword();
        // 前端传递到后端的密码进行过加密，需要使用 RSA 算法解密
        String rawPassword;
        try {
            rawPassword = RSAUtil.decrypt(password);
        } catch (Exception e) {
            throw new ConditionException("密码解密失败！");
        }
        String md5Password = MD5Util.sign(rawPassword, salt, "UTF-8");
        user.setSalt(salt);
        user.setPassword(md5Password);
        user.setCreateTime(now);
        user = userApi.addUser(user);
        // 添加用户信息
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(user.getId());
        userInfo.setNick(UserConstant.DEFAULT_NICK);
        userInfo.setBirth(UserConstant.DEFAULT_BIRTH);
        userInfo.setGender(UserConstant.GENDER_FEMALE);
        userInfo.setCreateTime(now);
        userApi.addUserInfo(userInfo);
        // 添加用户默认权限角色
        userAuthService.addUserDefaultRole(user.getId());
    }

    /**
     * 用户登录
     */
    public String login(User user) throws Exception {
        // 校验（同时支持手机号和邮箱）
        String phone = user.getPhone() == null ? "" : user.getPhone();
        String email = user.getEmail() == null ? "" : user.getEmail();
        if (StringUtils.isEmpty(phone) && StringUtils.isEmpty(email)) {
            throw new ConditionException("参数异常！");
        }
        User dbUser = userApi.getUserByPhoneOrEmail(phone, email);
        if (dbUser == null) {
            throw new ConditionException("当前用户不存在！");
        }
        String password = user.getPassword();
        // 前端传递到后端的密码进行过加密，需要使用 RSA 算法解密
        String rawPassword;
        try {
            rawPassword = RSAUtil.decrypt(password);
        } catch (Exception e) {
            throw new ConditionException("密码解密失败！");
        }
        // 对前端传递到后端的密码使用该用户的盐进行加密
        String salt = dbUser.getSalt();
        String md5Password = MD5Util.sign(rawPassword, salt, "UTF-8");
        // 如果加密后的结果和数据库的结果一致，表示密码正确
        if (!dbUser.getPassword().equals(md5Password)) {
            throw new ConditionException("密码错误！");
        }
        return TokenUtil.generateToken(dbUser.getId());
    }

    /**
     * 根据用户id获取用户信息
     */
    public User getUserInfo(Long userId) {
        User user = userApi.getUserById(userId);
        UserInfo userInfo = userApi.getUserInfoByUserId(userId);
        user.setUserInfo(userInfo);
        return user;
    }

    /**
     * 更新用户信息
     */
    public void updateUserInfos(UserInfo userInfo) {
        userInfo.setUpdateTime(new Date());
        userApi.updateUserInfos(userInfo);
    }

    /**
     * 更新用户
     */
    public void updateUsers(User user) throws Exception {
        Long id = user.getId();
        User dbUser = userApi.getUserById(id);
        if (dbUser == null) {
            throw new ConditionException("用户不存在！");
        }
        if (!StringUtils.isEmpty(user.getPassword())) {
            String rawPassword = RSAUtil.decrypt(user.getPassword());
            String md5Password = MD5Util.sign(rawPassword, dbUser.getSalt(), "UTF-8");
            user.setPassword(md5Password);
        }
        user.setUpdateTime(new Date());
        userApi.updateUsers(user);
    }

    /**
     * 分页查询用户
     */
    public PageResult<UserInfo> pageListUserInfos(JSONObject params) {
        Integer no = params.getInteger("no");
        Integer size = params.getInteger("size");
        params.put("start", (no - 1) * size);
        params.put("limit", size);
        Integer total = userApi.pageCountUserInfos(params);
        List<UserInfo> list = new ArrayList<>();
        if (total > 0) {
            Long userId = (Long) params.get("userId");
            list = userApi.pageListUserInfos(params);
            list = list.stream()
                    .filter(userInfo -> !Objects.equals(userInfo.getUserId(), userId)).collect(Collectors.toList());
        }
        return new PageResult<>(total, list);
    }

    /**
     * 存储refresh-token到数据库
     */
    public Map<String, Object> loginForDts(User user) throws Exception {
        String phone = user.getPhone() == null ? "" : user.getPhone();
        String email = user.getEmail() == null ? "" : user.getEmail();
        if (StringUtils.isEmpty(phone) && StringUtils.isEmpty(email)) {
            throw new ConditionException("参数异常！");
        }
        User dbUser = userApi.getUserByPhoneOrEmail(phone, email);
        if (dbUser == null) {
            throw new ConditionException("当前用户不存在！");
        }
        String password = user.getPassword();
        String rawPassword;
        try {
            rawPassword = RSAUtil.decrypt(password);
        } catch (Exception e) {
            throw new ConditionException("密码解密失败！");
        }
        String salt = dbUser.getSalt();
        String md5Password = MD5Util.sign(rawPassword, salt, "UTF-8");
        if (!md5Password.equals(dbUser.getPassword())) {
            throw new ConditionException("密码错误！");
        }
        Long userId = dbUser.getId();
        String accessToken = TokenUtil.generateToken(userId);
        String refreshToken = TokenUtil.generateRefreshToken(userId);
        //保存refresh token到数据库
        userApi.deleteRefreshTokenByUserId(userId);
        userApi.addRefreshToken(refreshToken, userId, new Date());
        Map<String, Object> result = new HashMap<>();
        result.put("accessToken", accessToken);
        result.put("refreshToken", refreshToken);
        return result;
    }

    /**
     * 用户退出则将refresh-token设置为无效
     */
    public void logout(String refreshToken, Long userId) {
        userApi.deleteRefreshToken(refreshToken, userId);
    }

    /**
     * 刷新access-token
     */
    public String refreshAccessToken(String refreshToken) throws Exception {
        RefreshTokenDetail refreshTokenDetail = userApi.getRefreshTokenDetail(refreshToken);
        if (refreshTokenDetail == null) {
            throw new ConditionException("555", "token过期！");
        }
        Long userId = refreshTokenDetail.getUserId();
        return TokenUtil.generateToken(userId);
    }

    /**
     * 根据用户id集合批量查询用户信息
     */
    public List<UserInfo> batchGetUserInfoByUserIds(Set<Long> userIdList) {
        return userApi.batchGetUserInfoByUserIds(userIdList);
    }
}
